package com.hsurosy.domain.strategy.service.rule.tree.factory.engine.impl;

import com.hsurosy.domain.strategy.model.valobj.RuleLogicCheckTypeVO;
import com.hsurosy.domain.strategy.model.valobj.RuleTreeNodeLineVO;
import com.hsurosy.domain.strategy.model.valobj.RuleTreeNodeVO;
import com.hsurosy.domain.strategy.model.valobj.RuleTreeVO;
import com.hsurosy.domain.strategy.service.rule.tree.ILogicTreeNode;
import com.hsurosy.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import com.hsurosy.domain.strategy.service.rule.tree.factory.engine.IDecisionTreeEngine;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Author Hsu琛君珩
 * @Date 2024-10-19 15:31
 * @Description 决策树引擎实现类
 * @Version: v1.0.0
 */
@Slf4j
public class DecisionTreeEngine implements IDecisionTreeEngine {

    // 决策树节点组，用于获取每个节点的具体逻辑处理
    private final Map<String, ILogicTreeNode> logicTreeNodeGroup; // "rule_stock": RuleStockLogicTreeNode、"rule_lock": RuleLockLogicTreeNode、"rule_luck_award": RuleLuckAwardLogicTreeNode
    // 当前规则树的结构信息
    private final RuleTreeVO ruleTreeVO;

    // 构造方法，初始化决策树引擎
    public DecisionTreeEngine(Map<String, ILogicTreeNode> logicTreeNodeGroup, RuleTreeVO ruleTreeVO) {
        this.logicTreeNodeGroup = logicTreeNodeGroup;
        this.ruleTreeVO = ruleTreeVO;
    }

    /**
     * 执行规则树的处理逻辑
     *
     * @param userId 用户ID
     * @param strategyId 抽奖策略ID
     * @param awardId 奖品ID
     * @return 处理后的奖品数据，包含奖品ID和奖品规则
     */
    @Override
    public DefaultTreeFactory.StrategyAwardVO process(String userId, Long strategyId, Integer awardId, Date endDateTime) {
        // 用于存储规则树最终处理得到的奖品数据（奖品ID和规则）
        DefaultTreeFactory.StrategyAwardVO strategyAwardData = null;

        // 获取规则树的根节点（即规则树的起始节点的标识符）
        String nextNode = ruleTreeVO.getTreeRootRuleNode();
        // 获取整个规则树的节点映射，通过节点Key可以找到对应的节点信息
        Map<String, RuleTreeNodeVO> treeNodeMap = ruleTreeVO.getTreeNodeMap(); // "rule_lock": RuleTreeNodeVO、"rule_stock": RuleTreeNodeVO、"rule_luck_award": RuleTreeNodeVO
        // 获取起始节点的详细信息
        RuleTreeNodeVO ruleTreeNode = treeNodeMap.get(nextNode);

        // 逐步遍历规则树中的节点，直到没有下一个节点为止
        while (null != nextNode) {
            // 1. 获取当前节点的逻辑处理类，通过节点的Key（规则Key）找到具体的逻辑处理类
            ILogicTreeNode logicTreeNode = logicTreeNodeGroup.get(ruleTreeNode.getRuleKey());
            String ruleValue = ruleTreeNode.getRuleValue();  // 获取节点的规则值

            // 2. 执行当前节点的逻辑处理，返回逻辑计算的结果
            // logic方法执行的是与该节点相关的业务逻辑
            DefaultTreeFactory.TreeActionEntity logicEntity = logicTreeNode.logic(userId, strategyId, awardId, ruleValue, endDateTime);

            // 获取该节点的规则检查结果
            RuleLogicCheckTypeVO ruleLogicCheckTypeVO = logicEntity.getRuleLogicCheckType();
            // 获取当前节点处理后的奖品数据
            strategyAwardData = logicEntity.getStrategyAwardVO();

            // 记录该节点的处理日志，包括规则树名称、树ID、当前节点和规则结果
            log.info("决策树引擎【{}】treeId:{} node:{} code:{}", ruleTreeVO.getTreeName(), ruleTreeVO.getTreeId(), nextNode, ruleLogicCheckTypeVO.getCode());

            // 3. 计算下一个要执行的节点，根据当前节点的规则检查结果，确定下一个节点
            nextNode = nextNode(ruleLogicCheckTypeVO.getCode(), ruleTreeNode.getTreeNodeLineVOList());
            // 更新当前节点为下一个节点
            ruleTreeNode = treeNodeMap.get(nextNode);
        }

        // 返回规则树最终计算得到的奖品数据
        return strategyAwardData;
    }

    /**
     * 根据当前节点的计算结果，获取下一个节点
     *
     * @param matterValue 当前节点的计算结果（规则检查码） ALLOW/TAKE_OVER
     * @param treeNodeLineVOList 当前节点的所有连接线，表示可能的下一个节点
     * @return 返回下一个节点的Key
     */
    public String nextNode(String matterValue, List<RuleTreeNodeLineVO> treeNodeLineVOList) {
        // 如果没有连线或连线列表为空，返回 null，表示规则树结束
        if (null == treeNodeLineVOList || treeNodeLineVOList.isEmpty()) {
            return null;
        }

        // 遍历所有可能的连接线，寻找符合当前规则结果的下一个节点
        for (RuleTreeNodeLineVO nodeLine : treeNodeLineVOList) {
            if (decisionLogic(matterValue, nodeLine)) {
                return nodeLine.getRuleNodeTo();  // 返回符合规则的下一个节点
            }
        }
        /**
         *  举例解释：
         *  1. rule_node_from = rule_lock，rule_node_to = rule_stock，rule_limit_type = EQUAL，rule_limit_value = "ALLOW"
         *  2. rule_node_from = rule_lock，rule_node_to = rule_luck_award，rule_limit_type = EQUAL，rule_limit_value = "TAKE_OVER"
         *  3. 在 rule_lock 节点计算出 matterValue 为 "ALLOW" 后：
         *      nextNode 会遍历 treeNodeLineVOList
         *      decisionLogic 判断第一个连接线符合条件（matterValue = "ALLOW"），所以 nextNode 返回 rule_stock
         8  4. 如果 matterValue 为 "TAKE_OVER"，则返回 rule_luck_award
         **/
        return null;
    }

    /**
     * 决策逻辑，判断当前节点是否符合连接线的规则
     *
     * @param matterValue 当前节点的规则检查码 ALLOW/TAKE_OVER
     * @param nodeLine 当前节点的连接线信息
     * @return 返回是否符合连接线规则
     */
    public boolean decisionLogic(String matterValue, RuleTreeNodeLineVO nodeLine) {
        // 根据规则限定类型，判断是否符合连接线规则
        switch (nodeLine.getRuleLimitType()) {
            case EQUAL:
                return matterValue.equals(nodeLine.getRuleLimitValue().getCode());  // 如果规则类型是"等于"，则判断值是否相等
            // 其他规则（大于、小于等）暂时未实现，可以根据需求扩展
            case GT:
            case LT:
            case GE:
            case LE:
            default:
                return false;
        }
    }

}
